package com.example.auth;

import com.sun.jna.platform.win32.Sspi;
import com.sun.jna.platform.win32.SspiUtil;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import waffle.windows.auth.IWindowsAuthProvider;
import waffle.windows.auth.IWindowsIdentity;
import waffle.windows.auth.IWindowsSecurityContext;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;

import java.util.Base64;

public class WaffleAuthHandler implements Handler<RoutingContext> {

    private static final Logger LOGGER = LoggerFactory.getLogger(WaffleAuthHandler.class);
    private final IWindowsAuthProvider authProvider = new WindowsAuthProviderImpl();
    private static final String SECURITY_CONTEXT_KEY = "waffleSecurityContext";

    @Override
    public void handle(RoutingContext ctx) {
        HttpServerResponse response = ctx.response();
        String header = ctx.request().getHeader("Authorization");

        if (header == null) {
            initiateNtlm(response);
            return;
        }

        if (!header.startsWith("Negotiate ")) {
            ctx.fail(400); // Bad request
            return;
        }

        byte[] token = Base64.getDecoder().decode(header.substring("Negotiate ".length()));
        String connectionId = ctx.session().id();

        try {
            IWindowsSecurityContext securityContext = authProvider.acceptSecurityToken(connectionId, token, "Negotiate");

            if (securityContext.isContinue()) {
                sendChallenge(response, securityContext.getToken());
            } else {
                IWindowsIdentity identity = securityContext.getIdentity();
                ctx.setUser(new WaffleUser(identity));
                LOGGER.info("Authentication successful for user: {}", identity.getFqn());
                securityContext.dispose();
                authProvider.resetSecurityToken(connectionId);
                ctx.next();
            }
        } catch (Exception e) {
            LOGGER.error("Error during Waffle authentication", e);
            authProvider.resetSecurityToken(connectionId);
            ctx.fail(401, e);
        }
    }

    private void initiateNtlm(HttpServerResponse response) {
        response.setStatusCode(401).putHeader("WWW-Authenticate", "Negotiate").end();
    }

    private void sendChallenge(HttpServerResponse response, byte[] token) {
        response.setStatusCode(401)
                .putHeader("WWW-Authenticate", "Negotiate " + Base64.getEncoder().encodeToString(token))
                .end();
    }
}